import re
import time
import subprocess
import traceback

def find_window(title_regex: str) -> int | None:
    try:
        with subprocess.Popen(['wmctrl', '-l'], stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as p:
            stdout, _ = p.communicate(timeout=3)
            stdout = stdout.decode()
        for line in stdout.splitlines():
            m = re.match(r'^0x([0-9a-f]+)\s+(\d+)\s+(.*?)\s+(.*)$', line)
            if m:
                title = m.group(4).strip()
                if re.search(title_regex, title):
                    return int(m.group(1), base=16)
        return None
    except:
        traceback.print_exc()
        return None

def goto_window(title_or_id: str | int):
    try:
        if isinstance(title_or_id, int):
            with subprocess.Popen(['wmctrl', '-iR', hex(title_or_id)], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) as p:
                p.wait(timeout=3)
        else:
            with subprocess.Popen(['wmctrl', '-R', title_or_id], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) as p:
                p.wait(timeout=3)
        return True
    except:
        traceback.print_exc()
        return False

def goto_or_start(title_regex: str, program: list[str] | None = None):
    id = find_window(title_regex)
    if id is not None:
        goto_window(id)
        return True
    if program:
        subprocess.Popen(program, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        duration = 0.06
        for _ in range(5):
            id = find_window(title_regex)
            if id is not None:
                goto_window(id)
                return True
            time.sleep(duration)
            duration *= 1.75
    return False

def get_current_window_title():
    try:
        win_title = subprocess.check_output(['xdotool', 'getwindowfocus', 'getwindowname']).decode()
        return win_title.strip()
    except:
        return ''

def get_current_window_bbox():
    result = subprocess.check_output([
        'xdotool', 'getwindowfocus', 'getwindowgeometry', '--shell',
    ]).decode()
    x = y = width = height = 0
    for line in result.splitlines():
        line = line.split('=')
        if len(line) == 2:
            if line[0] == 'X':
                x = int(line[1])
            elif line[0] == 'Y':
                y = int(line[1])
            elif line[0] == 'WIDTH':
                width = int(line[1])
            elif line[0] == 'HEIGHT':
                height = int(line[1])
    return x, y, x + width, y + height

def is_current_window_terminal():
    t = time.time()
    if hasattr(is_current_window_terminal, 'last_time') and t - is_current_window_terminal.last_time < 1:
        return is_current_window_terminal.last_res
    res = get_current_window_title().startswith('终端 -')
    is_current_window_terminal.last_res = res
    is_current_window_terminal.last_time = t
    return res
